﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using MediaLibrary.Controls;

using AMPLibrary.Collections;
using AMPLibrary.Controllers;
using AMPLibrary.Media;
using AMPLibrary.Windows;

namespace MediaLibrary
{
    /// <summary>
    /// Interaction logic for PlaylistPage.xaml
    /// </summary>
    public partial class PlaylistPage : Page
    {
        private int currentlyEditingIndex;

        private const double PLAYLIST_CHANGE_SHOWING_HEIGHT = 29.0f;

        private const double PLAYLIST_CHANGE_HIDDEN_HEIGHT = 0.0f;

        private PlaylistCollection playlistCollection = PlaylistCollection.GetPlaylistCollection();

        private AutomaticPlaylistCollection automaticPlaylistCollection = AutomaticPlaylistCollection.GetAutomaticPlaylistCollection();

        private WatchFolderController watchFolderController = WatchFolderController.GetWatchFolderController();

        //
        private bool IsDragging 
        { 
            get; 
            set; 
        }

        //
        private MediaFile DraggedMedia;

        /// <summary>
        /// 
        /// </summary>
        public PlaylistPage()
        {
            InitializeComponent();

            playlistCollection.ItemAdded += new ChangedEventHandler(playlistCollection_Changed);
            playlistCollection.ItemRemoved += new ChangedEventHandler(playlistCollection_Changed);
            playlistCollection.ItemsRemoved += new ChangedEventHandler(playlistCollection_Changed);
            playlistCollection.ItemsAdded += new ChangedEventHandler(playlistCollection_Changed);
            playlistCollection.ItemsChanged += new ChangedEventHandler(playlistCollection_Changed);

            watchFolderController.PlaylistScanComplete += new WatchFolderController.PlaylistScanCompleteEventHandler(watchFolderController_PlaylistScanComplete);
            watchFolderController.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(watchFolderController_PropertyChanged);

            currentPlaylistListView.ItemTemplateSelector = new PlaylistMediaDataTemplateSelector();

            savePlaylistRow.Height = new GridLength(0);

            currentlyEditingIndex = -1;

            this.myPlaylistsExpander.IsExpanded = true;
            this.automaticPlaylistExpander.IsExpanded = false;

            this.playlistGrid.Visibility = System.Windows.Visibility.Hidden;
            this.automaticPlaylistDetails.Visibility = System.Windows.Visibility.Hidden;

            BindContentMyPlaylists();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void newPlaylistButton_Click(object sender, RoutedEventArgs e)
        {
            NewPlaylistWindow npw = new NewPlaylistWindow(new Collection<MediaFile>());
            npw.Owner = (Window)this.Parent;

            if (npw.ShowDialog().Value == true)
            {
                PlaylistCollection playlistCollection = PlaylistCollection.GetPlaylistCollection();
                playlistCollection.AddItem(new Playlist() { Path = npw.PlaylistPath, Title = System.IO.Path.GetFileName(npw.PlaylistPath) });
            }

            BindContentMyPlaylists();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void newAutomaticPlaylistButton_Click(object sender, RoutedEventArgs e)
        {
            NewAutomaticPlaylistWindow napw = new NewAutomaticPlaylistWindow();
            napw.Owner = (Window)this.Parent;

            if (napw.ShowDialog().Value == true)
                BindContentAutomaticPlaylists();
        }

        /// <summary>
        /// 
        /// </summary>
        private void BindContentMyPlaylists()
        {
            BindMyPlaylists();
            BindAutomaticPlaylists();
            
            this.myPlaylistsExpander.IsExpanded = true;
            this.automaticPlaylistExpander.IsExpanded = false;

            this.playlistGrid.Visibility = System.Windows.Visibility.Hidden;
            this.automaticPlaylistDetails.Visibility = System.Windows.Visibility.Hidden;
        }

        /// <summary>
        /// 
        /// </summary>
        private void BindContentAutomaticPlaylists()
        {
            BindMyPlaylists();
            BindAutomaticPlaylists();

            this.myPlaylistsExpander.IsExpanded = false;
            this.automaticPlaylistExpander.IsExpanded = true;

            this.playlistGrid.Visibility = System.Windows.Visibility.Hidden;
            this.automaticPlaylistDetails.Visibility = System.Windows.Visibility.Hidden;
        }

        /// <summary>
        /// 
        /// </summary>
        private void BindMyPlaylists()
        {
            Pause();

            try
            {
                playlistListView.ItemsSource = (from p in playlistCollection orderby p.Title select p);
                playlistCountLabel.Content = "My Playlists: " + playlistListView.Items.Count.ToString() + "; Automatic Playlists: " + automaticPlaylistListView.Items.Count.ToString();
                currentPlaylistListView.ItemsSource = null;
                currentPlaylistListView.Items.Refresh();
            }
            catch
            {

            }

            Unpause();
        }

        /// <summary>
        /// 
        /// </summary>
        private void BindAutomaticPlaylists()
        {
            Pause();

            try
            {
                automaticPlaylistListView.ItemsSource = (from apc in automaticPlaylistCollection orderby apc.PlaylistName select apc);
                playlistCountLabel.Content = "My Playlists: " + playlistListView.Items.Count.ToString() + "; Automatic Playlists: " + automaticPlaylistListView.Items.Count.ToString();
                currentPlaylistListView.ItemsSource = null;
                currentPlaylistListView.Items.Refresh();
            }
            catch
            {

            }

            Unpause();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void playlistListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            Pause();

            if (playlistListView.SelectedIndex == -1)
                return;

            this.playlistGrid.Visibility = System.Windows.Visibility.Visible;
            this.automaticPlaylistDetails.Visibility = System.Windows.Visibility.Hidden;

            Mouse.OverrideCursor = System.Windows.Input.Cursors.Wait;

            if(savePlaylistRow.Height.Value == PLAYLIST_CHANGE_SHOWING_HEIGHT)
            {
                playlistListView.SelectedIndex = currentlyEditingIndex;
                return;
            }
            else
                currentlyEditingIndex = playlistListView.SelectedIndex;

            if (playlistListView.Items.Count > 0)
            {
                if (playlistListView.SelectedIndex == -1)
                    return;

                Playlist playlist = (Playlist)playlistListView.SelectedItem;
                if (playlist == null)
                    return;

                currentPlaylistListView.ItemsSource = Playlist.LoadPlaylist(playlist.Path);
            }

            Mouse.OverrideCursor = null;

            Unpause();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void automaticPlaylistListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            Pause();

            if (automaticPlaylistListView.SelectedIndex == -1)
                return;

            this.playlistGrid.Visibility = System.Windows.Visibility.Hidden;
            this.automaticPlaylistDetails.Visibility = System.Windows.Visibility.Visible;

            Mouse.OverrideCursor = System.Windows.Input.Cursors.Wait;

            if ((AutomaticPlaylist)automaticPlaylistListView.SelectedItem != null)
            {
                this.automaticPlaylistDetails.BindAutomaticPlaylist((AutomaticPlaylist)automaticPlaylistListView.SelectedItem);
                this.automaticPlaylistDetails.Visibility = System.Windows.Visibility.Visible;
            }

            Mouse.OverrideCursor = null;

            Unpause();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void deletePlaylistMenuItem_Click(object sender, RoutedEventArgs e)
        {
            Pause();

            if (playlistListView.SelectedItem == null)
                return;

            Playlist playlist = (Playlist)playlistListView.SelectedItem;
            if (playlist == null)
                return;

            playlistListView.SelectedIndex = -1;

            Playlist.DeletePlaylist(playlist.Path);
            BindContentMyPlaylists();

            Unpause();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void refreshButton_Click(object sender, EventArgs e)
        {
            BindContentMyPlaylists();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void addToNowPlayingMenuItem_Click(object sender, RoutedEventArgs e)
        {
            Pause();

            Mouse.OverrideCursor = System.Windows.Input.Cursors.Wait;

            if (playlistListView.SelectedItem == null)
                return;

            Playlist playlist = (Playlist)playlistListView.SelectedItem;

            if(playlist == null)
                return;

            NowPlayingCollection nowPlayingCollection = NowPlayingCollection.GetNowPlayingCollection();
            nowPlayingCollection.AddItems(new Collection<MediaFile>(currentPlaylistListView.ItemsSource.Cast<MediaFile>()));

            Mouse.OverrideCursor = null;

            Unpause();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void replaceNowPlayingMenuItem_Click(object sender, RoutedEventArgs e)
        {
            Pause();

            Mouse.OverrideCursor = System.Windows.Input.Cursors.Wait;

            if (playlistListView.SelectedItem == null)
                return;

            Playlist playlist = (Playlist)playlistListView.SelectedItem;

            if (playlist == null)
                return;

            NowPlayingCollection nowPlayingCollection = NowPlayingCollection.GetNowPlayingCollection();
            nowPlayingCollection.ClearItems();
            nowPlayingCollection.AddItems(new Collection<MediaFile>(currentPlaylistListView.ItemsSource.Cast<MediaFile>()));

            Mouse.OverrideCursor = null;

            Unpause();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void removeAllMenuItem_OnClick(object sender, EventArgs e)
        {
            Pause();

            this.currentPlaylistListView.ItemsSource = new Collection<MediaFile>();

            savePlaylistRow.Height = new GridLength(PLAYLIST_CHANGE_SHOWING_HEIGHT);

            Unpause();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void removeSelectedMenuItem_OnClick(object sender, EventArgs e)
        {
            Pause();

            Collection<MediaFile> mediaToSave = new Collection<MediaFile>();

            // get all the media
            foreach (MediaFile item in currentPlaylistListView.Items)
                mediaToSave.AddItem(item);

            // remove the selected media
            foreach (MediaFile media in this.currentPlaylistListView.SelectedItems)
                mediaToSave.RemoveItem(media);

            // rebind
            this.currentPlaylistListView.ItemsSource = mediaToSave;

            savePlaylistRow.Height = new GridLength(PLAYLIST_CHANGE_SHOWING_HEIGHT);

            Unpause();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cropMenuItem_OnClick(object sender, EventArgs e)
        {
            Pause();

            Collection<MediaFile> mediaToKeep = new Collection<MediaFile>();

            foreach (MediaFile item in this.currentPlaylistListView.Items)
            {
                if(this.currentPlaylistListView.SelectedItems.Contains(item))
                    mediaToKeep.AddItem(item);
            }

            this.currentPlaylistListView.ItemsSource = mediaToKeep;

            savePlaylistRow.Height = new GridLength(PLAYLIST_CHANGE_SHOWING_HEIGHT);

            Unpause();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void selectAllMenuItem_OnClick(object sender, EventArgs e)
        {
            Pause();

            currentPlaylistListView.SelectAll();

            Unpause();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void invertSelectionMenuItem_OnClick(object sender, EventArgs e)
        {
            Pause();

            Collection<MediaFile> mediaToSelect = new Collection<MediaFile>();

            foreach (MediaFile item in this.currentPlaylistListView.Items)
            {
                if (!this.currentPlaylistListView.SelectedItems.Contains(item))
                    mediaToSelect.AddItem(item);
            }

            this.currentPlaylistListView.SelectedItems.Clear();

            foreach (MediaFile item in mediaToSelect)
                this.currentPlaylistListView.SelectedItems.Add(item);

            Unpause();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void clearSelectionMenuItem_OnClick(object sender, EventArgs e)
        {
            Pause();

            currentPlaylistListView.SelectedItems.Clear();

            Unpause();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void randomizeMenuItem_OnClick(object sender, EventArgs e)
        {
            Pause();

            Collection<MediaFile> mediaToSave = new Collection<MediaFile>();

            foreach (MediaFile item in currentPlaylistListView.Items)
                mediaToSave.AddItem(item);

            mediaToSave.RandomizeItems();
            currentPlaylistListView.ItemsSource = mediaToSave;

            savePlaylistRow.Height = new GridLength(PLAYLIST_CHANGE_SHOWING_HEIGHT);

            Unpause();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void reverseListMenuItem_OnClick(object sender, EventArgs e)
        {
            Pause();

            Collection<MediaFile> mediaToSave = new Collection<MediaFile>();

            foreach (MediaFile item in currentPlaylistListView.Items)
                mediaToSave.AddItem(item);

            mediaToSave.ReverseItems();
            currentPlaylistListView.ItemsSource = mediaToSave;

            savePlaylistRow.Height = new GridLength(PLAYLIST_CHANGE_SHOWING_HEIGHT);

            Unpause();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void sortByTitleMenuItem_OnClick(object sender, EventArgs e)
        {
            Pause();

            Collection<MediaFile> mediaToSave = new Collection<MediaFile>();

            foreach (MediaFile item in currentPlaylistListView.Items)
                mediaToSave.AddItem(item);

            mediaToSave.Sort(new SortMediaByTitle());
            currentPlaylistListView.ItemsSource = mediaToSave;

            savePlaylistRow.Height = new GridLength(PLAYLIST_CHANGE_SHOWING_HEIGHT);

            Unpause();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void sortByPathMenuItem_OnClick(object sender, EventArgs e)
        {
            Pause();

            Collection<MediaFile> mediaToSave = new Collection<MediaFile>();

            foreach (MediaFile item in currentPlaylistListView.Items)
                mediaToSave.AddItem(item);

            mediaToSave.Sort(new SortMediaByPath());
            currentPlaylistListView.ItemsSource = mediaToSave;

            savePlaylistRow.Height = new GridLength(PLAYLIST_CHANGE_SHOWING_HEIGHT);

            Unpause();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void nowPlayingListView_OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            Pause();

            IsDragging = true;

            var listViewItem = VisualElementsHelper.TryFindFromPoint<System.Windows.Controls.ListViewItem>((UIElement)sender, e.GetPosition(currentPlaylistListView));
            if (listViewItem == null)
                return;

            //set flag that indicates we're capturing mouse movements
            IsDragging = true;
            DraggedMedia = (MediaFile)listViewItem.Content;

            Unpause();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            Pause();

            if (!IsDragging)
                return;

            if (currentPlaylistListView.SelectedItems.Count > 1)
                return;

            Collection<MediaFile> mediaToSave = new Collection<MediaFile>();

            foreach (MediaFile item in currentPlaylistListView.Items)
                mediaToSave.AddItem(item);

            //get the target item
            MediaFile targetItem = (MediaFile)currentPlaylistListView.SelectedItem;

            if (targetItem == null || !ReferenceEquals(DraggedMedia, targetItem))
            {
                //get target index
                var targetIndex = currentPlaylistListView.Items.IndexOf(targetItem);

                //remove the source from the list
                mediaToSave.RemoveItem(DraggedMedia);

                //move source at the target's location
                mediaToSave.InsertItem(targetIndex, DraggedMedia);

                currentPlaylistListView.ItemsSource = mediaToSave;

                //select the dropped item
                currentPlaylistListView.SelectedItem = DraggedMedia;
                
                savePlaylistRow.Height = new GridLength(PLAYLIST_CHANGE_SHOWING_HEIGHT);
            }

            IsDragging = false;

            Unpause();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnMouseMove(object sender, System.Windows.Input.MouseEventArgs e)
        {
            if (!IsDragging || e.LeftButton != MouseButtonState.Pressed)
                return;

            //make sure the row under the grid is being selected
            Point position = e.GetPosition(currentPlaylistListView);

            var uiElement = VisualElementsHelper.TryFindFromPoint<System.Windows.Controls.ListViewItem>(currentPlaylistListView, position);

            if (uiElement != null)
                currentPlaylistListView.SelectedItem = uiElement;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void savePlaylistButton_Click(object sender, RoutedEventArgs e)
        {
            Pause();

            Collection<MediaFile> mediaToSave = new Collection<MediaFile>();

            foreach (MediaFile item in currentPlaylistListView.Items)
                mediaToSave.AddItem(item);

            Playlist playlist = (Playlist)playlistListView.SelectedItem;
            if (playlist == null)
                return;

            Playlist.UpdatePlaylist(playlist.Path, mediaToSave);

            savePlaylistRow.Height = new GridLength(PLAYLIST_CHANGE_HIDDEN_HEIGHT);

            currentlyEditingIndex = -1;

            Unpause();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cancelChangesPlaylistButton_Click(object sender, RoutedEventArgs e)
        {
            Pause();

            if (playlistListView.Items.Count > 0)
            {
                if (playlistListView.SelectedIndex == -1)
                    playlistListView.SelectedIndex = 0;

                Playlist playlist = (Playlist)playlistListView.SelectedItem;
                if (playlist == null)
                    return;

                currentPlaylistListView.ItemsSource = Playlist.LoadPlaylist(playlist.Path);
            }

            savePlaylistRow.Height = new GridLength(PLAYLIST_CHANGE_HIDDEN_HEIGHT);

            currentlyEditingIndex = -1;

            Unpause();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void currentPlaylistListView_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            Pause();

            if (currentPlaylistListView.SelectedItem == null)
                return;

            NowPlayingCollection nowPlayingCollection = NowPlayingCollection.GetNowPlayingCollection();
            nowPlayingCollection.AddItem(currentPlaylistListView.SelectedItem as MediaFile);

            MediaFile media = (MediaFile)currentPlaylistListView.SelectedItem;

            AMPLibrary.Media.MediaPlayer.GetMediaPlayer().Play(ref media);

            Unpause();
        }

        /// <summary>
        /// Method, stops the music folder controller from scanning while the page is reading from the collection
        /// </summary>
        private void Pause()
        {
            watchFolderController.PauseMusic = true;
            watchFolderController.PauseVideo = true;
            watchFolderController.PausePlaylist = true;
            System.Threading.Thread.Sleep(100);
        }

        /// <summary>
        /// Method, tells the music folder controller to resume scanning
        /// </summary>
        private void Unpause()
        {
            watchFolderController.PauseMusic = false;
            watchFolderController.PauseVideo = false;
            watchFolderController.PausePlaylist = false;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void automaticPlaylistExpander_Expanded(object sender, RoutedEventArgs e)
        {
            myPlaylistsExpander.IsExpanded = false;
            playlistListView.SelectedIndex = -1;
            
            this.playlistGrid.Visibility = System.Windows.Visibility.Hidden;
            this.automaticPlaylistDetails.Visibility = System.Windows.Visibility.Hidden;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void myPlaylistsExpander_Expanded(object sender, RoutedEventArgs e)
        {
            automaticPlaylistExpander.IsExpanded = false;
            automaticPlaylistListView.SelectedIndex = -1;

            this.playlistGrid.Visibility = System.Windows.Visibility.Hidden;
            this.automaticPlaylistDetails.Visibility = System.Windows.Visibility.Hidden;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void watchFolderController_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "CurrentPlaylistFolder")
                this.currentlyScanning.Content = watchFolderController.CurrentPlaylistFolder;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void watchFolderController_PlaylistScanComplete(object sender, EventArgs e)
        {
            BindContentMyPlaylists();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void playlistCollection_Changed(object sender, EventArgs e)
        {
            BindContentMyPlaylists();
        }
    }
}
